/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package htmlparser;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import socof.wget.ExecutorDownloader;

/**
 *
 * @author Carlos
 */
public class HtmlParser
{

    private ArrayList<String> result;
    private String fileContent;
    private Document doc;
    private String domain;
    private String filePath;
    private String basePath;
    private int maxLevel = -1;

    public HtmlParser(String domain, String basePath, String filePath)
    {
        this.domain = domain.toLowerCase();
        this.filePath = filePath;
        this.result = new ArrayList();

        this.basePath = basePath.replace("\\", "/");
        if (this.basePath.charAt(this.basePath.length() - 1) == '/')
        {
            this.basePath = this.basePath.substring(0, this.basePath.length() - 1);
        }
    }

    public HtmlParser(String domain, String basePath, String filePath, int maxLevel)
    {
        this(domain, basePath, filePath);
        this.maxLevel = maxLevel;
    }

    public void parse()
    {
        try
        {
            this.fileContent = getFileContents(this.filePath);
            doc = Jsoup.parse(this.fileContent);
            doc.setBaseUri("http://" + this.domain);

            Elements links = doc.select("a[href]");
            Elements media = doc.select("[src]");
            Elements imports = doc.select("link[href]");

            // href ...
            for (Element link : links)
            {
                addElementLinkToList(link);
            }

            // img ...
            for (Element src : media)
            {
                addElementSrcToList(src);
            }

            // js, css, ...
            for (Element link : imports)
            {
                //result.add(link.attr("abs:href"));
                addElementLinkToList(link);
            }

            clearDuplicates();
        }
        catch (Exception ex)
        {
            Logger.getLogger(ExecutorDownloader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public List<String> getLinks()
    {
        return this.result;
    }

    public boolean saveFile()
    {
        BufferedWriter writer = null;
        try
        {
            writer = new BufferedWriter(new FileWriter(this.filePath));
            writer.write(doc.html());
        }
        catch (IOException e)
        {
            return false;
        }
        finally
        {
            try
            {
                if (writer != null)
                {
                    writer.close();
                }
            }
            catch (IOException e)
            {
                return false;
            }
        }
        return true;
    }

    private String getFileContents(String filePath)
    {
        //...checks on aFile are elided
        StringBuilder contents = new StringBuilder();

        try
        {
            //use buffering, reading one line at a time
            //FileReader always assumes default encoding is OK!
            BufferedReader input = new BufferedReader(new FileReader(filePath));
            try
            {
                String line = null;
                /*
                 * readLine is a bit quirky :
                 * it returns the content of a line MINUS the newline.
                 * it returns null only for the END of the stream.
                 * it returns an empty String if two newlines appear in a row.
                 */
                while ((line = input.readLine()) != null)
                {
                    contents.append(line);
                    contents.append(System.getProperty("line.separator"));
                }
            }
            finally
            {
                input.close();
            }
        }
        catch (IOException ex)
        {
            Logger.getLogger(ExecutorDownloader.class.getName()).log(Level.SEVERE, null, ex);
        }

        return contents.toString();
    }

    /**
     * Only adds elements from the same host
     *
     * @param Element e
     */
    private void addElementLinkToList(Element e)
    {
        try
        {
            String absUrl = e.absUrl("href");

            // Removes anchors
            if (absUrl.contains("#"))
            {
                absUrl = absUrl.substring(0, absUrl.lastIndexOf("#"));
            }

            URL tmp = new URL(absUrl);
            if (tmp.getHost().toLowerCase().contains(domain))
            {
                if (isInMaxLevel(absUrl))
                {
                    result.add(absUrl);

                    URL tmpUrl = new URL(absUrl);
                    String newHref = absUrl.replace(tmpUrl.getHost(), basePath + "/" + tmpUrl.getHost());
                    newHref = newHref.replace("http://", "file://");
                    e.attr("href", newHref);
                }
            }
        }
        catch (MalformedURLException ex)
        {
            Logger.getLogger(ExecutorDownloader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Only adds elements from the same host
     *
     * @param Element e
     */
    private void addElementSrcToList(Element e)
    {
        try
        {
            String absUrl = e.absUrl("src");

            // Removes anchors
            if (absUrl.contains("#"))
            {
                absUrl = absUrl.substring(0, absUrl.lastIndexOf("#"));
            }

            URL tmp = new URL(absUrl);
            if (tmp.getHost().toLowerCase().contains(domain))
            {
                if (isInMaxLevel(absUrl))
                {
                    result.add(absUrl);

                    URL tmpUrl = new URL(absUrl);
                    String newHref = absUrl.replace(tmpUrl.getHost(), basePath + "/" + tmpUrl.getHost());
                    newHref = newHref.replace("http://", "file://");
                    e.attr("src", newHref);
                }
            }
        }
        catch (MalformedURLException ex)
        {
            Logger.getLogger(ExecutorDownloader.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public boolean isInMaxLevel(String url)
    {
        String[] s = url.split("/");
        return this.maxLevel > 0 && (s.length) <= this.maxLevel + 3;
    }

    private void clearDuplicates()
    {
        final Set<String> setToReturn = new HashSet();

        for (String url : result)
        {
            setToReturn.add(url);
        }

        result.clear();
        result.addAll(setToReturn);
    }
}
